package com.ming.boot.captcha.util;

import lombok.extern.slf4j.Slf4j;
import org.springframework.util.Base64Utils;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;

/**
 * 图片工具类
 *
 * @author ming
 * @date 2019-10-28 21:07
 */
@Slf4j
public class ImgUtil {
    private static int blurDegree = 5;// 模糊度
    private static final String FILE_TYPE_PNG = "png";


    private static void readPixel(BufferedImage img, int x, int y, int[] pixels) {
        int xStart = x - 1;
        int yStart = y - 1;
        int current = 0;
        double sqrt = Math.sqrt(pixels.length);
        for (int i = xStart; i < sqrt + xStart; i++)
            for (int j = yStart; j < sqrt + yStart; j++) {
                int tx = i;
                if (tx < 0) {
                    tx = -tx;

                } else if (tx >= img.getWidth()) {
                    tx = x;
                }
                int ty = j;
                if (ty < 0) {
                    ty = -ty;
                } else if (ty >= img.getHeight()) {
                    ty = y;
                }
                pixels[current++] = img.getRGB(tx, ty);

            }
    }

    private static void fillMatrix(int[][] matrix, int[] values) {
        int filled = 0;
        for (int i = 0; i < matrix.length; i++) {
            int[] x = matrix[i];
            for (int j = 0; j < x.length; j++) {
                x[j] = values[filled++];
            }
        }
    }

    private static int avgMatrix(int[][] matrix) {
        int r = 0;
        int g = 0;
        int b = 0;
        for (int i = 0; i < matrix.length; i++) {
            int[] x = matrix[i];
            for (int j = 0; j < x.length; j++) {
                if (j == 1) {
                    continue;
                }
                Color c = new Color(x[j]);
                r += c.getRed();
                g += c.getGreen();
                b += c.getBlue();
            }
        }
        int l = matrix.length;
        return new Color(r >> l, g >> l, b >> l).getRGB();
    }

    /**
     * 切矩形图
     *
     * @param targetFile 目标文件
     * @param xLength 矩形的宽
     * @param yLength 矩形的高
     * @return 切图结果
     * @throws Exception - 抛异常
     */
    public static Map<String, Object> cutPictureByRect(File targetFile, int xLength, int yLength) throws Exception {
        Map<String, Object> pictureMap = new HashMap<>();
        // 原图
        BufferedImage oriImage = ImageIO.read(targetFile);
        int oriImageWidth = oriImage.getWidth();
        int oriImageHeight = oriImage.getHeight();
        //随机生成抠图坐标X,Y
        Random random = new Random();
        int x = random.nextInt(oriImageWidth - 2 * xLength) + xLength;
        if (x < blurDegree || x > oriImageWidth - blurDegree) {
            x = blurDegree;
        }
        int y = random.nextInt(oriImageHeight - yLength);
        if (y < blurDegree || y > oriImageHeight - blurDegree) {
            y = blurDegree;
        }
        log.info("原图大小{} x {},随机生成的坐标 X,Y 为（{}，{}）", oriImageWidth, oriImageHeight, x, y);

        // 新建一个指定大小的矩形图像
        BufferedImage newImage = new BufferedImage(xLength, yLength, oriImage.getType());
        //得到画笔对象
        Graphics2D graphics = newImage.createGraphics();
        //如果需要生成RGB格式，需要做如下配置,Transparency 设置透明
        newImage = graphics.getDeviceConfiguration().createCompatibleImage(xLength, yLength, Transparency.TRANSLUCENT);

        // 抠图
        cutByRect(oriImage, newImage, x, y, xLength, yLength);

        // 设置“抗锯齿”的属性
        graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        graphics.drawImage(newImage, 0, 0, null);
        graphics.dispose();

        ByteArrayOutputStream newImageOs = new ByteArrayOutputStream();
        ImageIO.write(newImage, FILE_TYPE_PNG, newImageOs);
        byte[] newImageByte = newImageOs.toByteArray();

        ByteArrayOutputStream oriImagesOs = new ByteArrayOutputStream();
        ImageIO.write(oriImage, FILE_TYPE_PNG, oriImagesOs);
        byte[] oriImageByte = oriImagesOs.toByteArray();

        pictureMap.put("smallImg", Base64Utils.encodeToString(newImageByte));
        pictureMap.put("bigImg", Base64Utils.encodeToString(oriImageByte));
        pictureMap.put("x", x);
        pictureMap.put("y", y);
        return pictureMap;
    }


    /**
     * 裁剪一个矩形
     *
     * @param oriImage -原图
     * @param newImage -裁剪好的矩形图
     * @param x        X坐标
     * @param y        Y坐标
     * @param xLength  矩形宽度
     * @param yLength  矩形高度
     */
    private static void cutByRect(BufferedImage oriImage, BufferedImage newImage, int x, int y, int xLength, int yLength) {
        //临时数组遍历用于高斯模糊存周边像素值
        int[][] matrix = new int[blurDegree][blurDegree];
        int[] values = new int[blurDegree * blurDegree];

        int borderRgb = Color.gray.getRGB();
        // 矩形图宽度
        for (int i = 0; i < xLength; i++) {
            // 矩形图高度
            for (int j = 0; j < yLength; j++) {
                newImage.setRGB(i, j, oriImage.getRGB(x + i, y + j));
                // 模糊处理
                readPixel(oriImage, x + i, y + j, values);
                fillMatrix(matrix, values);
                oriImage.setRGB(x + i, y + j, avgMatrix(matrix));

                oriImage.setRGB(x, y + j, borderRgb);// 左边框
                oriImage.setRGB(x + xLength, y + j, borderRgb);// 右边框
            }
            oriImage.setRGB(x + i, y, borderRgb);// 上边框
            oriImage.setRGB(x + i, y + yLength, borderRgb);// 下边框
        }

    }
}
